package org.ncibi.cytoscape.metscape.ui;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import org.ncibi.cytoscape.metscape.data.CompoundData;
import org.ncibi.cytoscape.metscape.data.ConceptData;
import org.ncibi.cytoscape.metscape.data.GeneData;
import org.ncibi.cytoscape.metscape.data.Organism;
import org.ncibi.cytoscape.metscape.data.QuerySubtype;
import org.ncibi.cytoscape.metscape.data.QueryType;
import org.ncibi.cytoscape.metscape.plugin.MetScapePlugin;
import org.ncibi.cytoscape.metscape.task.BuildNetworkTask;
import org.ncibi.cytoscape.metscape.task.OutputFileTask;
import org.ncibi.cytoscape.metscape.ui.table.ExtendedJTable;
import org.ncibi.cytoscape.metscape.ui.table.ExtendedTableModel;
import org.ncibi.cytoscape.metscape.utils.FileUtils;
import org.ncibi.cytoscape.metscape.utils.NumUtils;
import org.ncibi.cytoscape.metscape.utils.WebUtils;
import org.ncibi.metab.network.NetworkType;
import org.ncibi.metab.network.node.CompoundNode;
import org.ncibi.metab.network.node.GeneNode;
import org.ncibi.metab.network.node.MetabolicNode;
import org.ncibi.metab.pathway.Pathway;
import org.ncibi.metab.ws.client.MetabolicNodesService;
import org.ncibi.metab.ws.client.MetabolicPathwaysService;
import org.ncibi.ws.HttpRequestType;
import org.ncibi.ws.Response;

import cytoscape.Cytoscape;
import cytoscape.util.CyNetworkNaming;
import cytoscape.view.cytopanels.CytoPanel;
import cytoscape.view.cytopanels.CytoPanelState;

@SuppressWarnings("serial")
public class BuildNetworkPanel extends JPanel  {
	
	private JLabel panelLabel;
	private JButton clearAllButton;
	private JButton closeButton;
	
	private JPanel inputPanel;
	private TitledBorder inputBorder;
	
	private JLabel organismLabel;
	private JComboBox organismComboBox;
	
	private JPanel experimentalDataPanel;
	private TitledBorder experimentalDataBorder;
	private JLabel experimentalDataLabel;
	private JButton selectDataButton;
	
	private JPanel compoundsPanel;
	private TitledBorder compoundsBorder;
	private JButton compoundsLookupButton;
	private ExtendedJTable compoundsTable;
	private ExtendedTableModel compoundsTableModel;
	private JScrollPane compoundsScrollPane;
	private JButton compoundsAddButton;
	private JButton compoundsRemoveButton;
	private JButton compoundsClearButton;
	private JButton compoundsResetButton;
	
	private JPanel genesPanel;
	private TitledBorder genesBorder;
	private ExtendedJTable genesTable;
	private ExtendedTableModel genesTableModel;
	private JScrollPane genesScrollPane;
	private JButton genesAddButton;
	private JButton genesRemoveButton;
	private JButton genesClearButton;
	private JButton genesResetButton;
	
	private JPanel optionsPanel;
	private TitledBorder optionsBorder;
	private JPanel networkTypePanel;
	private TitledBorder networkTypeBorder;
	private JComboBox networkTypeComboBox;
	
	private JPanel queryPanel;
	private TitledBorder queryBorder;
	private ButtonGroup queryGroup;
	private JRadioButton useCompoundsGenes;
	private JComboBox compoundsGenesComboBox;
	private JRadioButton usePathway;
	private JComboBox pathwayComboBox;
	
	private JButton buildNetworkButton;
	private JButton outputAsFileButton;
	
	public BuildNetworkPanel() {
		createControls();
	}
	
	private void createControls() {
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		
		panelLabel = new JLabel("Build Network");
		clearAllButton = new JButton("Clear All");
		clearAllButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				clearAll();
			}
		});
		closeButton = new JButton("Close");
		closeButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				close();
		}});
		add(new Box(BoxLayout.X_AXIS) {
			{
				add(panelLabel);
				add(Box.createHorizontalGlue());
				add(clearAllButton);
				add(closeButton);
			}
		});
		
		inputPanel = new JPanel();
		inputBorder = BorderFactory.createTitledBorder("Input");
		inputBorder.setTitleFont(inputBorder.getTitleFont().deriveFont(Font.BOLD));
		inputPanel.setBorder(inputBorder);
		inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
		inputPanel.setAlignmentX(CENTER_ALIGNMENT);
		
		organismLabel = new JLabel("Organism");
		organismComboBox = new JComboBox();
		for(Organism organism: Organism.values() ) {
			organismComboBox.addItem(organism);
		}
		organismComboBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				switchOrganism();
			}
		});
		updateOrganism();
		inputPanel.add(new Box(BoxLayout.X_AXIS) {
			{
				setAlignmentX(RIGHT_ALIGNMENT);
				add(organismLabel);
				add(Box.createHorizontalStrut(5));
				add(organismComboBox);
			}
		});
		
		
		experimentalDataPanel = new JPanel();
		experimentalDataPanel.setLayout(new BoxLayout(experimentalDataPanel, BoxLayout.Y_AXIS));
		experimentalDataPanel.setAlignmentX(CENTER_ALIGNMENT);
		experimentalDataBorder = BorderFactory.createTitledBorder("Experimental Data");
		experimentalDataPanel.setBorder(experimentalDataBorder);
		experimentalDataLabel = new JLabel();
		updateFilesLabel();
		selectDataButton = new JButton("Select...");
		selectDataButton.setAlignmentX(RIGHT_ALIGNMENT);
		experimentalDataPanel.add(selectDataButton);
		experimentalDataPanel.add(new Box(BoxLayout.Y_AXIS) {
			{
				setAlignmentX(RIGHT_ALIGNMENT);
				add(experimentalDataLabel);
			}
		});
		selectDataButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				selectData();
			}
		});
		inputPanel.add(experimentalDataPanel);
		
		compoundsPanel = new JPanel();
		compoundsPanel.setLayout(new BoxLayout(compoundsPanel, BoxLayout.Y_AXIS));
		compoundsBorder = BorderFactory.createTitledBorder("Compounds");
		compoundsPanel.setBorder(compoundsBorder);
		compoundsPanel.setAlignmentX(CENTER_ALIGNMENT);
		compoundsLookupButton = new JButton("Compound Lookup");
		compoundsLookupButton.setAlignmentX(RIGHT_ALIGNMENT);
		compoundsLookupButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				WebUtils.openCompoundLookup();
			}
		});
        compoundsPanel.add(compoundsLookupButton);
		compoundsTable = new ExtendedJTable();
		compoundsTableModel = (ExtendedTableModel) compoundsTable.getModel();
		Vector<?> currentCompounds = MetScapePlugin.getPluginData().getCurrentCompounds();
		Vector<?> compoundColumns = new Vector<String>(Arrays.asList(new String[]{"Input ID", "Compound Name"}));
		if(currentCompounds != null) {
			compoundsTableModel.setDataVector(currentCompounds, compoundColumns);
		}
		else {
			MetScapePlugin.getPluginData().setCurrentCompounds(compoundsTableModel.getDataVector());
			compoundsTableModel.setColumnIdentifiers(compoundColumns);
			resetCompounds();
		}
		compoundsTableModel.addTableModelListener(new TableModelListener() {
			public void tableChanged(TableModelEvent e) {
				updateStatus();
			}
		});
		compoundsTable.getRowSorter().toggleSortOrder(0);
		compoundsScrollPane = new JScrollPane(compoundsTable);
		compoundsScrollPane.setAlignmentX(RIGHT_ALIGNMENT);
		compoundsPanel.add(compoundsScrollPane);
		compoundsAddButton = new JButton("Add");
		compoundsAddButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addToCompounds();
			}
		});
		compoundsRemoveButton = new JButton("Remove");
		compoundsRemoveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				removeFromCompounds();
			}
		});
		compoundsClearButton = new JButton("Clear");
		compoundsClearButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				clearCompounds();
			}
		});
		compoundsResetButton = new JButton("Reset");
		compoundsResetButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				resetCompounds();
			}
		});
		compoundsPanel.add(new Box(BoxLayout.X_AXIS) {
			{
				setAlignmentX(RIGHT_ALIGNMENT);
				add(Box.createHorizontalGlue());
				add(compoundsAddButton);
				add(compoundsRemoveButton);
				add(compoundsClearButton);
				add(compoundsResetButton);
				add(Box.createHorizontalGlue());
			}
		});
		inputPanel.add(compoundsPanel);
		
		genesPanel = new JPanel();
		genesPanel.setLayout(new BoxLayout(genesPanel, BoxLayout.Y_AXIS));
		genesBorder = BorderFactory.createTitledBorder("Genes");
		genesPanel.setBorder(genesBorder);
		genesPanel.setAlignmentX(CENTER_ALIGNMENT);
		genesTable = new ExtendedJTable();
		genesTableModel = (ExtendedTableModel) genesTable.getModel();
		Vector<?> currentGenes = MetScapePlugin.getPluginData().getCurrentGenes();
		Vector<?> geneColumns = new Vector<String>(Arrays.asList(new String[]{"Input ID", "Human Gene Symbol"}));
		if(currentGenes != null) {
			genesTableModel.setDataVector(currentGenes, geneColumns);
		}
		else {
			MetScapePlugin.getPluginData().setCurrentGenes(genesTableModel.getDataVector());
			genesTableModel.setColumnIdentifiers(geneColumns);
			resetGenes();
		}
		genesTableModel.addTableModelListener(new TableModelListener() {
			public void tableChanged(TableModelEvent e) {
				updateStatus();
			}
		});
		genesTable.getRowSorter().toggleSortOrder(0);
		genesScrollPane = new JScrollPane(genesTable);
		genesScrollPane.setAlignmentX(RIGHT_ALIGNMENT);
		genesPanel.add(genesScrollPane);
		genesAddButton = new JButton("Add");
		genesAddButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addToGenes();
			}
		});
		genesRemoveButton = new JButton("Remove");
		genesRemoveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				removeFromGenes();
			}
		});
		genesClearButton = new JButton("Clear");
		genesClearButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				clearGenes();
			}
		});
		genesResetButton = new JButton("Reset");
		genesResetButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				resetGenes();
			}
		});
		genesPanel.add(new Box(BoxLayout.X_AXIS) {
			{
				setAlignmentX(RIGHT_ALIGNMENT);
				add(Box.createHorizontalGlue());
				add(genesAddButton);
				add(genesRemoveButton);
				add(genesClearButton);
				add(genesResetButton);
				add(Box.createHorizontalGlue());
			}
		});
		inputPanel.add(genesPanel);
		add(inputPanel);
		
		optionsPanel = new JPanel();
		optionsBorder = BorderFactory.createTitledBorder("Options");
		optionsBorder.setTitleFont(optionsBorder.getTitleFont().deriveFont(Font.BOLD));
		optionsPanel.setBorder(optionsBorder);
		optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS));
		optionsPanel.setAlignmentX(CENTER_ALIGNMENT);
		
		networkTypePanel = new JPanel();
		networkTypeBorder = BorderFactory.createTitledBorder("Network Type");
		networkTypePanel.setBorder(networkTypeBorder);
		networkTypePanel.setLayout(new BoxLayout(networkTypePanel, BoxLayout.Y_AXIS));
		networkTypePanel.setAlignmentX(CENTER_ALIGNMENT);
		networkTypeComboBox = new JComboBox(NetworkType.values());
		if(MetScapePlugin.getPluginData().getCurrentNetworkType() != null) {
			networkTypeComboBox.setSelectedItem(MetScapePlugin.getPluginData().getCurrentNetworkType());
		}
		networkTypeComboBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				updateCompoundTypeStatus();
				MetScapePlugin.getPluginData().setCurrentNetworkType((NetworkType)networkTypeComboBox.getSelectedItem());
			}
		});
		networkTypePanel.add(networkTypeComboBox);
		networkTypePanel.add(Box.createHorizontalGlue());
		optionsPanel.add(networkTypePanel);
		
		queryPanel = new JPanel();
		queryBorder = BorderFactory.createTitledBorder("Query");
		queryPanel.setBorder(queryBorder);
		queryPanel.setLayout(new BoxLayout(queryPanel, BoxLayout.Y_AXIS));
		queryPanel.setAlignmentX(CENTER_ALIGNMENT);
		queryGroup = new ButtonGroup();
		useCompoundsGenes = new JRadioButton("Use compounds/genes");
		useCompoundsGenes.setSelected(true);
		useCompoundsGenes.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MetScapePlugin.getPluginData().setCurrentQueryType(QueryType.COMPOUND_GENE);
				compoundsGenesComboBox.setEnabled(true);
				pathwayComboBox.setEnabled(false);
				updateStatus();
			}
		});
		queryGroup.add(useCompoundsGenes);
		compoundsGenesComboBox = new JComboBox();
		compoundsGenesComboBox.setVisible(false);
		queryPanel.add(new Box(BoxLayout.X_AXIS) {
			{
				setAlignmentX(LEFT_ALIGNMENT);
				add(useCompoundsGenes);
				add(compoundsGenesComboBox);
			}
		});
		Set<Pathway> pathways = MetScapePlugin.getPluginData().getDefaultPathways();
		if(pathways == null) {
			MetabolicPathwaysService pathwayService = new MetabolicPathwaysService(HttpRequestType.POST);
			Response<Set<Pathway>> pathwayResponse = pathwayService.retrievePathways();
			pathways = pathwayResponse.getResponseValue();
			if(pathways == null) 
				pathways = new LinkedHashSet<Pathway>();
			MetScapePlugin.getPluginData().setDefaultPathways(pathways);
		}
		usePathway = new JRadioButton("Use selected pathway");
		if(pathways.isEmpty())
			usePathway.setEnabled(false);
		usePathway.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MetScapePlugin.getPluginData().setCurrentQueryType(QueryType.PATHWAY);
				compoundsGenesComboBox.setEnabled(false);
				pathwayComboBox.setEnabled(true);
				updateStatus();
			}
		});
		queryGroup.add(usePathway);
		queryPanel.add(usePathway);
		pathwayComboBox = new JComboBox(pathways.toArray());
		pathwayComboBox.setPrototypeDisplayValue("");
		pathwayComboBox.setAlignmentX(LEFT_ALIGNMENT);
		if(MetScapePlugin.getPluginData().getCurrentPathway() != null) {
			pathwayComboBox.setSelectedItem(MetScapePlugin.getPluginData().getCurrentPathway());
		}
		else for(Pathway pathway: pathways) {
			if(pathway.getName().equals("TCA cycle")) {
				pathwayComboBox.setSelectedItem(pathway);
				break;
			}	
		}
		pathwayComboBox.addPopupMenuListener(new PopupMenuListener() {
			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
				updateStatus();
				MetScapePlugin.getPluginData().setCurrentPathway((Pathway)pathwayComboBox.getSelectedItem());
			}
			public void popupMenuCanceled(PopupMenuEvent e) {}
			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
		});
		queryPanel.add(pathwayComboBox);
		queryPanel.add(Box.createVerticalStrut(7));
		if(MetScapePlugin.getPluginData().getCurrentQueryType() == QueryType.PATHWAY){
			pathwayComboBox.setEnabled(true);
			compoundsGenesComboBox.setEnabled(false);
		}
		else {
			compoundsGenesComboBox.setEnabled(true);
			pathwayComboBox.setEnabled(false);
		}
		
		optionsPanel.add(queryPanel);
		add(optionsPanel);
		
		buildNetworkButton = new JButton("Build Network");
		buildNetworkButton.setAlignmentX(CENTER_ALIGNMENT);
		buildNetworkButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				buildNetwork();
			}
		});
		
		buildNetworkButton.setEnabled(false);
		add(buildNetworkButton);
		
		outputAsFileButton = new JButton("Output as File...");
		outputAsFileButton.setAlignmentX(CENTER_ALIGNMENT);
		outputAsFileButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outputAsFile();
			}
		});
		outputAsFileButton.setEnabled(false);
		
		add(new Box(BoxLayout.X_AXIS) {
			{
				add(buildNetworkButton);
				add(outputAsFileButton);
			}
		});
		updateStatus();
		if(MetScapePlugin.getPluginData().getCurrentQuerySubtype() == null) {
			compoundsGenesComboBox.setSelectedItem((QuerySubtype)MetScapePlugin.getPluginData().getCurrentQuerySubtype());
		}
		setPreferredSize(getMinimumSize());
	}
	
	private void clearAll() {
		organismComboBox.setSelectedIndex(0);
		clearData();

		for(int i=0; i<=pathwayComboBox.getItemCount(); i++) {
			Pathway pathway = (Pathway) pathwayComboBox.getItemAt(i);
			if(pathway.getName().equals("TCA cycle")) {
				pathwayComboBox.setSelectedItem(pathway);
				break;
			}	
		}
		useCompoundsGenes.setSelected(true);
		pathwayComboBox.setEnabled(false);
		networkTypeComboBox.setSelectedIndex(0);
		refresh();
	}
	
	public void refresh() {
		updateOrganism();
		updateFilesLabel();
		resetCompounds();
		resetGenes();
		updateStatus();
	}
	
	public void close() {
		CytoPanel cytoPanel = ((CytoPanel) getParent().getParent());
		cytoPanel.remove(BuildNetworkPanel.this);
		if(cytoPanel.getCytoPanelComponentCount() <= 0)
			cytoPanel.setState(CytoPanelState.HIDE);
		MetScapePlugin.getPluginData().setBuildNetworkPanelOpen(false);
	}
	
	private void switchOrganism() {
		if(MetScapePlugin.getPluginData().getCurrentOrganism() != organismComboBox.getSelectedItem()) {
			MetScapePlugin.getPluginData().setCurrentOrganism((Organism) organismComboBox.getSelectedItem());
			clearData();
			refresh();
		}
	}
	
	private void selectData() {
		if(SelectDataDialog.selectExperimentalData()) {
			refresh();
		}
	}
	
	private void clearData() {
		MetScapePlugin.getPluginData().setCurrentCompoundData(new CompoundData());
		MetScapePlugin.getPluginData().setCurrentGeneData(new GeneData());
		MetScapePlugin.getPluginData().setCurrentConceptData(new ConceptData());
		MetScapePlugin.getPluginData().setCompoundFoldChangeColumn(null);
		MetScapePlugin.getPluginData().setCompoundFoldChangeThreshold(null);
		MetScapePlugin.getPluginData().setCompoundPvalueColumn(null);
		MetScapePlugin.getPluginData().setCompoundPvalueThreshold(null);
		MetScapePlugin.getPluginData().setGeneFoldChangeColumn(null);
		MetScapePlugin.getPluginData().setGeneFoldChangeThreshold(null);
		MetScapePlugin.getPluginData().setGenePvalueColumn(null);
		MetScapePlugin.getPluginData().setGenePvalueThreshold(null);
		
		MetScapePlugin.getPluginData().getDefaultCompounds().clear();
		MetScapePlugin.getPluginData().getDefaultGenes().clear();
	}
	
	
	private void addToCompounds() {
		String compoundString = "";
		while(compoundString.equals("")) {
			compoundString = JOptionPane.showInputDialog(this, "Enter one or more compound IDs, separated by spaces.",
					"Add Compounds", JOptionPane.PLAIN_MESSAGE);
			if(compoundString == null) return;
			else if(compoundString.equals("")) {
				JOptionPane.showMessageDialog
				(this, "At least one compound ID is needed to proceed.", "Input Needed", JOptionPane.ERROR_MESSAGE);
			}
		}
		
		List<String> compounds = NumUtils.toUppercaseList(compoundString);
		if(compounds == null || compounds.size() <= 0)
			JOptionPane.showMessageDialog
			(this, "Valid input shall consist only of one or more compound IDs separated by whitespace.", "Invalid Input", JOptionPane.ERROR_MESSAGE);
		else {
			MetabolicNodesService service = new MetabolicNodesService(
					HttpRequestType.POST);
			Response<Set<MetabolicNode>> serverResponse = 
				service.retrieveCompoundsWithInteractions(compounds);
			Set<MetabolicNode> nodesSet = serverResponse.getResponseValue();
			Collection<String> missingCompounds = new ArrayList<String>(compounds);
			for(MetabolicNode node: nodesSet) {
				String id = CompoundNode.getCid(node);
				boolean containsNode = false;
				for(int i=0; i<compoundsTableModel.getRowCount(); i++) {
					if(compoundsTableModel.getValueAt(i, 0).equals(id)) {
						containsNode = true;
						break;
					}
				}
				if(!containsNode)
					compoundsTableModel.addRow(new Object[]{id,CompoundNode.getName(node)});
				missingCompounds.remove(id);
			}
			if (!missingCompounds.isEmpty()) {
				MissingDataDialog dialog = new MissingDataDialog(
						Cytoscape.getDesktop(), missingCompounds, null, null);
				dialog.setVisible(true);
			}
		}
	}
	
	private void removeFromCompounds() {
		int selectedRowCount = compoundsTable.getSelectedRowCount();
		for(int i=0; i<selectedRowCount; i++) {
			compoundsTableModel.removeRow(
					compoundsTable.convertRowIndexToModel
					(compoundsTable.getSelectedRow()));
		}
	}
	
	private void clearCompounds() {
		compoundsTableModel.setRowCount(0);
	}
	
	private void resetCompounds() {
		compoundsTableModel.setRowCount(0);
		Map<String, String> compounds = MetScapePlugin.getPluginData().getDefaultCompounds();
		if(compounds != null && !compounds.isEmpty()) {
			for(String id: compounds.keySet()) {
				compoundsTableModel.addRow
					(new Object[]{id,
							compounds.get(id)});
			}
		}
	}
	
	private void addToGenes() {
		String geneString = "";
		while(geneString.equals("")) {
			geneString = JOptionPane.showInputDialog(this, "Enter one or more gene IDs, separated by spaces.",
					"Add Genes", JOptionPane.PLAIN_MESSAGE);
			if(geneString == null) return;
			else if(geneString.equals("")) {
				JOptionPane.showMessageDialog
				(this, "At least one gene ID is needed to proceed.", "Input Needed", JOptionPane.ERROR_MESSAGE);
			}
		}
		
		List<Integer> genes = NumUtils.toIntegerList(geneString);
		if(genes == null || genes.size() <= 0)
			JOptionPane.showMessageDialog
			(this, "Valid input shall consist only of one or more numeric gene IDs separated by whitespace.", "Invalid Input", JOptionPane.ERROR_MESSAGE);
		else {
			MetabolicNodesService service = new MetabolicNodesService(
					HttpRequestType.POST);
			Response<Set<MetabolicNode>> serverResponse = 
				service.retrieveGenesWithInteractions(genes,MetScapePlugin.getPluginData().getCurrentOrganism().getTaxid());
			Set<MetabolicNode> nodesSet = serverResponse.getResponseValue();
			Collection<Integer> missingGenes = new ArrayList<Integer>(genes);
			for(MetabolicNode node: nodesSet) {
				Integer id = GeneNode.getOrganismGeneid(node);
				boolean containsNode = false;
				for(int i=0; i<genesTableModel.getRowCount(); i++) {
					if(genesTableModel.getValueAt(i, 0).equals(id)) {
						containsNode = true;
						break;
					}
				}
				if(!containsNode)
					genesTableModel.addRow(new Object[]{id,GeneNode.getSymbol(node)});
				missingGenes.remove(id);
			}
			if (!missingGenes.isEmpty()) {
				MissingDataDialog dialog = new MissingDataDialog(
						Cytoscape.getDesktop(), null, missingGenes, null);
				dialog.setVisible(true);
			}
		}
	}
	
	private void removeFromGenes() {
		int selectedRowCount = genesTable.getSelectedRowCount();
		for(int i=0; i<selectedRowCount; i++)
			genesTableModel.removeRow(
					genesTable.convertRowIndexToModel
					(genesTable.getSelectedRow()));
	}
	
	private void clearGenes() {
		genesTableModel.setRowCount(0);
	}
	private void resetGenes() {
		genesTableModel.setRowCount(0);
		Map<Integer, String> genes = MetScapePlugin.getPluginData().getDefaultGenes();
		if(genes != null && !genes.isEmpty()) {
			for(Integer id: genes.keySet()) {
					genesTableModel.addRow
					(new Object[]{id,genes.get(id)});
			}
		}
	}
	
	private void updateOrganism() {
		organismComboBox.setSelectedItem(MetScapePlugin.getPluginData().getCurrentOrganism());
	}
	
	private void updateFilesLabel() {
		String compoundsName = "(none)";
		if(MetScapePlugin.getPluginData().getCurrentCompoundData() != null)
			compoundsName = MetScapePlugin.getPluginData().getCurrentCompoundData().getName();
		String genesName = "(none)";
		if(MetScapePlugin.getPluginData().getCurrentGeneData() != null)
			genesName = MetScapePlugin.getPluginData().getCurrentGeneData().getName();
		String conceptsName = "(none)";
		if(MetScapePlugin.getPluginData().getCurrentConceptData() != null)
			conceptsName = MetScapePlugin.getPluginData().getCurrentConceptData().getName();
		experimentalDataLabel.setText("<html>Compounds: "+compoundsName
				+ "<br>Genes: " + genesName+
				"<br>Concepts: " + conceptsName+ "<br></html>");
	}
	
	private void updateStatus() {
		updateCompoundTypeStatus();
		updateBuildNetworkStatus();
	}
	
	private void updateCompoundTypeStatus() {
		Object selected = compoundsGenesComboBox.getSelectedItem();
		compoundsGenesComboBox.removeAllItems();
		if(networkTypeComboBox.getSelectedItem() == NetworkType.COMPOUND) {
			if(compoundsTableModel.getRowCount() > 0) {
				compoundsGenesComboBox.addItem(QuerySubtype.COMPOUNDS);
			}
			if(genesTableModel.getRowCount() > 0) {
				compoundsGenesComboBox.addItem(QuerySubtype.GENES);
			}
			useCompoundsGenes.setText("Use");
			compoundsGenesComboBox.setVisible(true);
		}
		else { // not compound network
			compoundsGenesComboBox.setVisible(false);
			useCompoundsGenes.setText("Use compounds/genes");
		}
		if(compoundsGenesComboBox.getItemCount() > 0) {
			compoundsGenesComboBox.setEnabled(true);
			if(selected != null){
				compoundsGenesComboBox.setSelectedItem(selected);
			}
			else{
				compoundsGenesComboBox.setSelectedIndex(0);
			}
		}
		else {
			compoundsGenesComboBox.setEnabled(false);
		}
	}

	private void updateBuildNetworkStatus() {
		if((genesTableModel.getRowCount() > 0) ||
				(compoundsTableModel.getRowCount() > 0) || 
				(usePathway.isSelected() && 
						!pathwayComboBox.getSelectedItem().equals("")) ) {
			buildNetworkButton.setEnabled(true);
			outputAsFileButton.setEnabled(true);
		}
		else {
			buildNetworkButton.setEnabled(false);
			outputAsFileButton.setEnabled(false);
		}
	}
	
	private List<String> getCompounds() {
		List<String> compoundIds = null;
		compoundIds = new ArrayList<String>();
		for(int i=0; i < compoundsTableModel.getRowCount(); i++)
			compoundIds.add((String)compoundsTableModel.getValueAt(i, 0));
		return compoundIds;
	}
	
	private List<Integer> getGenes() {
		List<Integer> geneIds = null;
		geneIds = new ArrayList<Integer>();
		for(int i=0; i < genesTableModel.getRowCount(); i++)
			geneIds.add((Integer) genesTableModel.getValueAt(i, 0));
		return geneIds;
	}
	
	private void buildNetwork() {
		List<String> compoundIds = getCompounds();
		List<Integer> geneIds = getGenes();
		NetworkType networkType = (NetworkType) networkTypeComboBox.getSelectedItem();
		if(useCompoundsGenes.isSelected()) {
			String networkName = CyNetworkNaming.getSuggestedNetworkTitle(networkType.toLongName());
			if (networkType == NetworkType.COMPOUND) {
				// remove possible conflicting lists
				if (compoundsGenesComboBox.getSelectedItem() == QuerySubtype.COMPOUNDS) {
					geneIds = new ArrayList<Integer>();
				} else {
					compoundIds = new ArrayList<String>();
				}
			}
			BuildNetworkTask.newNetwork(compoundIds,geneIds,null,networkType,networkName);
		}
		else if(usePathway.isSelected()) {
			Pathway pathway = (Pathway) pathwayComboBox.getSelectedItem();
			String networkName = CyNetworkNaming.getSuggestedNetworkTitle
				(pathway.getName() + " (" + networkType.toLongName() + ")");
			BuildNetworkTask.newNetwork(compoundIds,geneIds,pathway.getId(),networkType,networkName);
		}
	}
	
	private void outputAsFile() {
		File outputFile = FileUtils.getFile("Output as File", FileUtils.SAVE, "csv", "CSV File");
		if(outputFile != null) {
			List<String> compoundIds = getCompounds();
			List<Integer> geneIds = getGenes();
			if(useCompoundsGenes.isSelected()) {
				OutputFileTask.doOutput(compoundIds,geneIds,null,outputFile);
			}
			else if(usePathway.isSelected()){
				Pathway pathway = (Pathway) pathwayComboBox.getSelectedItem();
				OutputFileTask.doOutput(compoundIds,geneIds,pathway.getId(),outputFile);
			}
		}
	}
}
